package com.cxx.purchasecharge.component.controller;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.cxx.purchasecharge.component.bean.AccountingBean;
import com.cxx.purchasecharge.component.bean.ActionResult;
import com.cxx.purchasecharge.component.bean.ActionResult.ActionResultStatus;
import com.cxx.purchasecharge.component.bean.DataGridRequestForm;
import com.cxx.purchasecharge.component.bean.GenericPagingResult;
import com.cxx.purchasecharge.component.bean.LoginUser;
import com.cxx.purchasecharge.component.bean.PCApplicationContext;
import com.cxx.purchasecharge.component.bean.SearchRequestForm;
import com.cxx.purchasecharge.component.exception.ApplicationException;
import com.cxx.purchasecharge.component.utils.AjaxUtils;
import com.cxx.purchasecharge.component.utils.BeanConvertUtils;
import com.cxx.purchasecharge.component.utils.ComponentConstants;
import com.cxx.purchasecharge.component.utils.MessageProperties;
import com.cxx.purchasecharge.core.model.AccountingSearchForm;
import com.cxx.purchasecharge.core.model.persistence.Accounting;
import com.cxx.purchasecharge.dal.AccountingDao;
import com.cxx.purchasecharge.service.QueryService;

@Controller
@RequestMapping ("/expense")
public class AccountingManager
{
    private static final Logger logger = Logger.getLogger (AccountingManager.class);

    @Autowired
    private AccountingDao expenseDao;
    @Autowired
    private QueryService queryService;
    @Autowired
    private PCApplicationContext pcContext;

    @RequestMapping (value = "/")
    public String redirectToMainPage ()
    {
        return "accountingManagement";
    }

    @RequestMapping (value = "/getExpenses", method = RequestMethod.POST)
    public @ResponseBody
    String getExpenses (DataGridRequestForm dataGridRequestForm, SearchRequestForm searchRequestForm,
                        HttpServletRequest request) throws Exception
    {
        logger.debug (dataGridRequestForm);
        int page = dataGridRequestForm.getPage () - 1;
        int size = dataGridRequestForm.getRows ();
        String sortField = parseSortField (dataGridRequestForm.getSort ());
        String order = dataGridRequestForm.getOrder ();
        Pageable pageable = new PageRequest (page, size, new Sort ("asc".equalsIgnoreCase (order) ? Direction.ASC
                                                                                                 : Direction.DESC,
                                                                   sortField));
        LoginUser loginUser = pcContext.getLoginUser (request);
        if (null != loginUser)
        {
            AccountingSearchForm searchForm = BeanConvertUtils.searchRequestForm2AccountingSearchForm (searchRequestForm);
            Page <Accounting> expensePage = expenseDao.findPageAccountingBy (searchForm, pageable);
            float sumOutMoney = expenseDao.countExpenseBy (searchForm);
            float sumInMoney = expenseDao.countIncomeBy (searchForm);
            List <Map <String, String>> footer = new ArrayList <Map <String, String>> ();
            Map <String, String> map = new HashMap <String, String> ();
            map.put ("mode", "支出合计");
            map.put ("money", sumOutMoney + "");
            footer.add (map);
            map = new HashMap <String, String> ();
            map.put ("mode", "收入合计");
            map.put ("money", sumInMoney + "");
            footer.add (map);
            map = new HashMap <String, String> ();
            map.put ("mode", "总计");
            map.put ("money", (sumInMoney - sumOutMoney) + "");
            footer.add (map);

            long total = expensePage.getTotalElements ();
            GenericPagingResult <AccountingBean> expensePagingResult = new GenericPagingResult <AccountingBean> ();
            expensePagingResult.setRows (BeanConvertUtils.accountingList2AccountingBeanList (expensePage.getContent ()));
            expensePagingResult.setTotal (total);
            expensePagingResult.setFooter (footer);

            JSONObject jsonObject = JSONObject.fromObject (expensePagingResult);
            return jsonObject.toString ();
        }
        else
        {
            throw new ApplicationException ();
        }
    }

    private String parseSortField (final String sortField)
    {
        String sortFieldAfterParse = ComponentConstants.EXPENSE_CREATE;
        if (!StringUtils.isBlank (sortField))
        {
            if (ComponentConstants.EXPENSE_TYPE.equalsIgnoreCase (sortField))
            {
                sortFieldAfterParse = ComponentConstants.EXPENSE_TYPE_DOT_NAME;
            }
            else if (ComponentConstants.EXPENSE_CREATE_DATE.equalsIgnoreCase (sortField))
            {
                sortFieldAfterParse = ComponentConstants.EXPENSE_CREATE;
            }
            else if (ComponentConstants.EXPENSE_UPDATE_DATE.equalsIgnoreCase (sortField))
            {
                sortFieldAfterParse = ComponentConstants.EXPENSE_UPDATE;
            }
        }
        return sortFieldAfterParse;
    }

    @RequestMapping (value = "/newExpense", method = RequestMethod.POST)
    public @ResponseBody
    String addExpense (AccountingBean expenseBean, BindingResult result, HttpServletRequest request)
    {
        if (result.hasErrors ())
        {
            logger.error (result.getAllErrors ());
            ActionResult ar = ActionResult.badRequest ()
                                          .withMessage (MessageProperties.getConfig (ComponentConstants.GENERIC_MSG_REQUEST_ARGS_ERROR))
                                          .build ();
            return AjaxUtils.getJsonObject (ar);
        }
        else
        {
            Accounting expense = BeanConvertUtils.accountingBean2Accounting (expenseBean);
            expense.setUpdated(expense.getCreated());
            String userId = AjaxUtils.getUserIdFromRequest(pcContext, request);
            if(null != userId) 
            {
                expense.setUserCreatedBy(queryService.getUniqueIdByUserId(userId));
                expense.setUserUpdatedBy(queryService.getUniqueIdByUserId(userId));
            }
            ActionResult ar = ActionResult.createActionResult ().build ();

            try
            {
                expenseDao.save (expense);
                ar = ActionResult.ok ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_ADD_SUCCESS,
                                                                                     ComponentConstants.MSG_EXPENSE_TYPE))
                                 .build ();
            }
            catch (Exception e)
            {
                ar = ActionResult.serverError ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_ADD_FAIL,
                                                                                     ComponentConstants.MSG_EXPENSE_TYPE))
                                 .build ();
                logger.error (e.getMessage (), e);
            }

            return AjaxUtils.getJsonObject (ar);
        }
    }

    @RequestMapping (value = "/updateExpense", method = RequestMethod.POST)
    public @ResponseBody
    String updateExpense (AccountingBean expenseBean, BindingResult result, HttpServletRequest request)
    {
        if (result.hasErrors ())
        {
            logger.error (result.getAllErrors ());
            ActionResult ar = ActionResult.badRequest ()
                                          .withMessage (MessageProperties.getConfig (ComponentConstants.GENERIC_MSG_REQUEST_ARGS_ERROR))
                                          .build ();
            return AjaxUtils.getJsonObject (ar);
        }
        else
        {
            Accounting expense = BeanConvertUtils.accountingBean2Accounting (expenseBean);
            expense.setUpdated(new Date());
            String userId = AjaxUtils.getUserIdFromRequest(pcContext, request);
            if(null != userId) 
            {
                expense.setUserUpdatedBy(queryService.getUniqueIdByUserId(userId));
            }
            ActionResult ar = ActionResult.createActionResult ().build ();

            try
            {
                expenseDao.save (expense);
                ar = ActionResult.ok ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_UPDATE_SUCCESS,
                                                                                     ComponentConstants.MSG_EXPENSE_TYPE))
                                 .build ();
            }
            catch (Exception e)
            {
                logger.error (e.getMessage (), e);
                ar = ActionResult.serverError ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_UPDATE_SUCCESS,
                                                                                     ComponentConstants.MSG_EXPENSE_TYPE))
                                 .build ();
            }

            return AjaxUtils.getJsonObject (ar);
        }
    }

    @RequestMapping (value = "/delExpense", method = RequestMethod.POST)
    public @ResponseBody
    String deleteExpense (@RequestParam String ids)
    {
        if (null != ids && ids.trim ().length () > 0)
        {
            List <Accounting> expenses = new ArrayList <Accounting> ();
            Accounting expense;
            if (ids.indexOf (";") != -1)
            {
                String[] idArr = ids.split (";");
                for (String typeId : idArr)
                {
                    expense = new Accounting ();
                    long expenseId = Long.parseLong (typeId);
                    expense.setId (expenseId);
                    expenses.add (expense);
                }
            }
            else
            {
                expense = new Accounting ();
                long expenseId = Long.parseLong (ids);
                expense.setId (expenseId);
                expenses.add (expense);
            }

            ActionResult ar = ActionResult.createActionResult ().build ();
            try
            {
                expenseDao.delete (expenses);
                ar = ActionResult.ok ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_DELETE_SUCCESS,
                                                                                     ComponentConstants.MSG_EXPENSE_TYPE))
                                 .build ();
            }
            catch (Exception e)
            {
                logger.error (e.getMessage (), e);
                ar = ActionResult.serverError ()
                                 .withMessage (MessageProperties.getConfigFormatted (ComponentConstants.GENERIC_MSG_DELETE_SUCCESS,
                                                                                     ComponentConstants.MSG_EXPENSE_TYPE))
                                 .build ();
            }

            return AjaxUtils.getJsonObject (ar);
        }
        else
        {
            logger.error (ActionResultStatus.BAD_REQUEST + " ids=" + ids + " when delete expense type");
            ActionResult ar = ActionResult.badRequest ()
                                          .withMessage (MessageProperties.getConfig (ComponentConstants.GENERIC_MSG_REQUEST_ARGS_ERROR))
                                          .build ();
            return AjaxUtils.getJsonObject (ar);
        }
    }
}
